type $planet__get_callback__poof$<T, prop extends keyof T> = (proxy: T, value: T[prop])=>T[prop];
type $planet__set_callback__poof$<T, prop extends keyof T> = (proxy: T, old: T[prop], value: T[prop])=>T[prop];

/** 代理拦截数据 */
export type $planet_DataBlocker_poof$<T> = {
	$planet_get_poof$?: {[prop in keyof T]?: $planet__get_callback__poof$<T, prop>}&{ignore?: Array<abd.$planet_OmitKeys_poof$<T, Function>>},
	$planet_set_poof$?: {[prop in keyof T]?: $planet__set_callback__poof$<T, prop>}&{ignore?: Array<abd.$planet_OmitKeys_poof$<T, Function>>},
	$planet_afterSet_poof$?: (prop: string|symbol, old: any, value: any, hdl: $planet_PxiHandle_poof$<T>)=>void;
}

export class $planet_PxiHandle_poof$<T extends Object|Array<any>> implements ProxyHandler<T>{

	constructor(private $planet_tgt_poof$: T, private $planet_name_poof$: string, private $planet_prt_poof$: $planet_PxiHandle_poof$<any>, private $planet_blocker_poof$?:$planet_DataBlocker_poof$<T>){
		if($planet_blocker_poof$) this.$planet_in_poof$($planet_blocker_poof$);
		this.$planet_revocable_poof$ = Proxy.revocable($planet_tgt_poof$, this);
		this.$planet_old_poof$ = (Array.isArray($planet_tgt_poof$)?[]:{}) as T;
		this.$planet_backup_poof$();
	}

	private $planet_getGetCall_poof$<prop extends keyof T>(key: prop): $planet__get_callback__poof$<T, prop>{
		let call: $planet__get_callback__poof$<T, prop>;
		if(this.$planet_blocker_poof$ && this.$planet_blocker_poof$.$planet_get_poof$ && Reflect.has(this.$planet_blocker_poof$.$planet_get_poof$, key)) call = Reflect.get(this.$planet_blocker_poof$.$planet_get_poof$, key) as $planet__get_callback__poof$<T, prop>;
		return call;
	}

	private $planet_getSetCall_poof$<prop extends keyof T>(key: prop): $planet__set_callback__poof$<T, prop>{
		let call: $planet__set_callback__poof$<T, prop>;
		if(this.$planet_blocker_poof$ && this.$planet_blocker_poof$.$planet_set_poof$ && Reflect.has(this.$planet_blocker_poof$.$planet_set_poof$, key)) call = Reflect.get(this.$planet_blocker_poof$.$planet_set_poof$, key) as $planet__set_callback__poof$<T, prop>;
		return call;
	}

	private $planet_backup_poof$(key?: any){
		let value: any;
		if(key===undefined){
			value = abd.$planet_cloneData_poof$(this.$planet_target_poof$);
			this.$planet_old_poof$ = value;
		}else{
			value = Reflect.get(this.$planet_target_poof$, key);
			value = abd.$planet_cloneData_poof$(value);
			Reflect.set(this.$planet_old_poof$, key, value);
		}

		return value;
	}

	valueOf(){
		let temp: any;
		if(Array.isArray(this.$planet_tgt_poof$)){
			temp = [];
			let proxy = this.$planet_proxy_poof$ as Array<any>;
			for(let i = 0; i < proxy.length; i++) temp.push(Reflect.get(proxy, i));
		}else{
			temp = {};
			let proxy = this.$planet_proxy_poof$ as Object;
			Reflect.ownKeys(proxy).forEach(key=>Reflect.set(temp, key, Reflect.get(proxy, key)));
		}

		return temp as T;
	}

	private async $planet_publish_poof$(key: string|symbol, old: any, value: any){
		if(key!==undefined){
			let path = this.$planet_path_poof$ + '.' + String(key);
			$planet_DataManager_poof$.$planet_publish_poof$(path, old, value);
		}

		if(this.$planet_parent_poof$) this.$planet_parent_poof$.$planet_publish_poof$(this.$planet_name_poof$, this.$planet_old_poof$, this.$planet_target_poof$);
	}

	public $planet_in_poof$(blocker: $planet_DataBlocker_poof$<T>){
		if(this.$planet_blocker_poof$ === undefined) this.$planet_blocker_poof$ = {};
		let props: any[] = [];
		if(Reflect.has(blocker, 'get')){
			if(this.$planet_blocker_poof$.$planet_get_poof$ === undefined) this.$planet_blocker_poof$.$planet_get_poof$ = {};
			Reflect.ownKeys(blocker.$planet_get_poof$).forEach(p=>{
				Reflect.set(this.$planet_blocker_poof$.$planet_get_poof$, p, Reflect.get(blocker.$planet_get_poof$, p));
				if(!props.includes(p)) props.push(p);
			});
		}
		if(Reflect.has(blocker, 'set')){
			if(this.$planet_blocker_poof$.$planet_set_poof$ === undefined) this.$planet_blocker_poof$.$planet_set_poof$ = {};
			Reflect.ownKeys(blocker.$planet_set_poof$).forEach(p=>{
				Reflect.set(this.$planet_blocker_poof$.$planet_set_poof$, p, Reflect.get(blocker.$planet_set_poof$, p));
				if(!props.includes(p)) props.push(p);
			});
		}
		Reflect.ownKeys(blocker).filter(k=>!['get', 'set'].includes(k as any))
		.forEach(p=>Reflect.has(blocker, p)?Reflect.set(this.$planet_blocker_poof$, p, Reflect.get(blocker, p)):void 0);

		props.filter(p=>{
			let value = Reflect.get(this.$planet_tgt_poof$, p);
			return typeof value === 'object' && value !== null;
		}).forEach(p=>{
			let value = Reflect.get(this.$planet_tgt_poof$, p);
			if(!this.$planet_children_poof$.has(p) || this.$planet_children_poof$.get(p).$planet_target_poof$!==value){
				let handle = $planet_DataManager_poof$.$planet_proxy_poof$(value, String(p), this).$planet_handle_poof$;
				this.$planet_children_poof$.set(p, handle);
			}
		});
	}

	/** 销毁所有代理 */
	public $planet_destroy_poof$(){
		this.$planet_children_poof$.forEach(h=>h.$planet_destroy_poof$());
		this.$planet_children_poof$.clear();
		$planet_DataManager_poof$.$planet_destroy_poof$(this);
		this.$planet_revocable_poof$.revoke();
	}

	get(target: T, prop: string|symbol, receiver: any): T[keyof T]{
		let value: any;
		if(this.$planet_blocker_poof$?.$planet_get_poof$?.ignore?.includes(prop as any)) value = Reflect.get(target, prop);
		else{
			value = this.$planet_children_poof$.has(prop) ? this.$planet_children_poof$.get(prop).$planet_proxy_poof$ : Reflect.get(target, prop);

			if(typeof value === 'function') value = Reflect.apply(Function.bind, value, [receiver]);
			else{
				let call = this.$planet_getGetCall_poof$(prop as any);
				value = call ? call(receiver, value) : value;
			}
		}

		if(typeof value === 'object' && value !== null && !this.$planet_children_poof$.has(prop)){
			let handle = $planet_DataManager_poof$.$planet_proxy_poof$(value, String(prop), this).$planet_handle_poof$;
			this.$planet_children_poof$.set(prop, handle);
		}

		return value;
	}

	set(target: T, prop: string|symbol, value: any, receiver: any): boolean{
		if(this.$planet_blocker_poof$ && this.$planet_blocker_poof$.$planet_set_poof$ && this.$planet_blocker_poof$.$planet_set_poof$.ignore && this.$planet_blocker_poof$.$planet_set_poof$.ignore.includes(prop as any)){
			Reflect.set(target, prop, undefined);
			return true;
		}

		let old = this.$planet_backup_poof$(prop);

		let call = this.$planet_getSetCall_poof$(prop as any);
		if(typeof value === 'object' && value !== null && !this.$planet_children_poof$.has(prop)){
			let handle = $planet_DataManager_poof$.$planet_proxy_poof$(value, String(prop), this).$planet_handle_poof$;
			this.$planet_children_poof$.set(prop, handle);
		}

		let new_value = call ? call(receiver, old, value) : value;
		if(this.$planet_children_poof$.has(prop) && this.$planet_children_poof$.get(prop).$planet_target_poof$ !== new_value){
			let hdl = this.$planet_children_poof$.get(prop);
			if(!new_value){
				hdl.$planet_destroy_poof$();
				this.$planet_children_poof$.delete(prop);
			}else if(Array.isArray(new_value)){
				hdl.$planet_proxy_poof$.splice(0, hdl.$planet_proxy_poof$.length);
				hdl.$planet_proxy_poof$.push(...new_value);
			}else Object.assign(hdl.$planet_proxy_poof$, new_value);
		}

		Reflect.set(target, prop, this.$planet_children_poof$.has(prop) ? this.$planet_children_poof$.get(prop).valueOf() : new_value);

		if(this.$planet_blocker_poof$?.$planet_afterSet_poof$) this.$planet_blocker_poof$.$planet_afterSet_poof$(prop, old, new_value, this);

		this.$planet_publish_poof$(prop, old, new_value);

		return true;
	}

	private $planet_revocable_poof$: ReturnType<typeof Proxy.revocable>;
	private $planet_old_poof$: T;
	/** 本级代理 */
	public get $planet_proxy_poof$(){
		return this.$planet_revocable_poof$.proxy as T;
	}
	/** 代理对象 */
	public get $planet_target_poof$(){
		return this.$planet_tgt_poof$;
	}
	/** 父级handle */
	public get $planet_parent_poof$(){
		return this.$planet_prt_poof$;
	}
	/** 子级handle */
	private $planet_children_poof$ = new Map<any, $planet_PxiHandle_poof$<any>>();
	/** 当前handle的路径 */
	public get $planet_path_poof$(): string{
		return this.$planet_parent_poof$ ? this.$planet_parent_poof$.$planet_path_poof$+'.'+this.$planet_name_poof$ : this.$planet_name_poof$;
	}
}

export class $planet_DataManager_poof${

    /** 代理句柄映射 */
	private static $planet_id_map_poof$: Map<any, string> = new Map();
	private static $planet_record_poof$: Map<string, [any, any, $planet_PxiHandle_poof$<any>]> = new Map();

    /**
     * 生成代理对象
     * @param ins 数据实例
     * @param name 数据名称
     */
    public static $planet_proxy_poof$<I extends Object>(ins: I, name?: string, parent: $planet_PxiHandle_poof$<any> = null){
		let $planet_proxy_poof$: I, $planet_handle_poof$: $planet_PxiHandle_poof$<I>;
		if(this.$planet_id_map_poof$.has(ins)){
			let id = this.$planet_id_map_poof$.get(ins);
			let [target, pxi, handle] = this.$planet_record_poof$.get(id);
			$planet_proxy_poof$ = pxi, handle = handle;
		}else{
			let now = Date.now();
			let id = [now, String(Math.round(Math.random()*100000)).padStart(5, '0')].join(':');
			while(this.$planet_record_poof$.has(id)) id = [now, String(Math.round(Math.random()*100000)).padStart(5, '0')].join(':');

			//let result = createProxy(ins, name??id);
			$planet_handle_poof$ = new $planet_PxiHandle_poof$(ins, name??id, parent);
			$planet_proxy_poof$ = $planet_handle_poof$.$planet_proxy_poof$;

			[ins, $planet_handle_poof$, $planet_handle_poof$.$planet_proxy_poof$].forEach(i=>this.$planet_id_map_poof$.set(i, id));
			this.$planet_record_poof$.set(id, [ins, $planet_handle_poof$.$planet_proxy_poof$, $planet_handle_poof$]);
		}

        return {$planet_proxy_poof$, $planet_handle_poof$};
    }

	/** 是否已注册代理 */
	public static $planet_hasProxy_poof$(ins: any){
		return this.$planet_id_map_poof$.has(ins);
	}

	/**
	 * 初始化一个代理
	 * @param target 代理对象
	 * @param save 是否需要本地存储
	 * @param init 初始化句柄的回调
	 * @returns
	 */
	public static $planet_initProxy_poof$<D>(name: string, target: D, save: boolean = false, blocker?: $planet_DataBlocker_poof$<D>, prefix?: string){
		let result = $planet_DataManager_poof$.$planet_proxy_poof$(target, name);
		if(save){
			let item_key = (prefix??'')+name;
			abd.$planet_local_poof$.$planet_read_poof$(item_key, target);
			result.$planet_handle_poof$.$planet_in_poof$({
				$planet_afterSet_poof$(prop, old, valu, handle){
					abd.$planet_local_poof$.$planet_save_poof$(item_key, handle.$planet_target_poof$);
				}
			});
		}

		if(blocker) result.$planet_handle_poof$.$planet_in_poof$(blocker);

		Reflect.set(globalThis, 'data_'+name, result.$planet_proxy_poof$);

		return result.$planet_proxy_poof$
	}

	/** 销毁监听代理和记录 */
    public static $planet_destroy_poof$<D extends Object>(data: D){
		if(this.$planet_id_map_poof$.has(data)){
			let id = this.$planet_id_map_poof$.get(data);
			let [ins, pxi, handle] = this.$planet_record_poof$.get(id);
			[ins, pxi, handle].forEach(i=>this.$planet_id_map_poof$.delete(i));
			let path_list: string[] = [];
			let path = handle.$planet_path_poof$;
			this.$planet_call_pool_poof$.forEach((l, p)=>p.startsWith(path)?path_list.push(p):void 0);
			path_list.forEach(p=>this.$planet_call_pool_poof$.delete(p));
			handle.$planet_destroy_poof$();
			this.$planet_record_poof$.delete(id);
		}
    }


	private static $planet_monitor_call_poof$ = new Map<string, Array<(path: string, old: any, value: any)=>void>>();
	public static $planet_monitor_poof$(data: Object, call: (path: string, old: any, value: any)=>void){
		let id = this.$planet_id_map_poof$.get(data);
		let [ins, pxi, hdl] = this.$planet_record_poof$.get(id);
		let path = hdl.$planet_path_poof$;
		if(!this.$planet_monitor_call_poof$.has(path)) this.$planet_monitor_call_poof$.set(path, []);
		this.$planet_monitor_call_poof$.get(path).push(call);
	}

	public static $planet_free_poof$(data: Object){
		let id = this.$planet_id_map_poof$.get(data);
		let [ins, pxi, hdl] = this.$planet_record_poof$.get(id);
		let path = hdl.$planet_path_poof$;
		if(this.$planet_monitor_call_poof$.has(path)) this.$planet_monitor_call_poof$.delete(path);
	}

    /** 监听回调池 */
    private static $planet_call_pool_poof$: Map<string, Function[]> = new Map();
    /**
     * 注册监听
     * @param data 要监听的数据
     * @param key 要监听的字段
     * @param call 更新时触发的回调函数
     * @param update 是否在注册时触发回调
     */
    public static $planet_follow_poof$<D extends Object, K extends abd.$planet_OmitKeys_poof$<D, Function>>(data: D, key: K, call: (old_value: D[K], new_value: D[K])=>void, update: boolean = true){
        let handle: $planet_PxiHandle_poof$<D>;
        if(this.$planet_id_map_poof$.has(data)) handle = this.$planet_record_poof$.get(this.$planet_id_map_poof$.get(data))[2];
        else abd.$planet_log_poof$.$planet_tag_poof$('无法对未代理的实例进行监听: orange', data);

        let path = handle.$planet_path_poof$ + '.' + key.toString();
		if(!this.$planet_call_pool_poof$.has(path)) this.$planet_call_pool_poof$.set(path, []);
		this.$planet_call_pool_poof$.get(path).push(call);

        if(update){
			let [target, proxy] = this.$planet_record_poof$.get(this.$planet_id_map_poof$.get(data));
			call(target[key], proxy[key]);
		}

        return {path, call} as {path: string, call: Function};
    }

	/** 注销监听 */
	public static $planet_cancel_poof$(info: ReturnType<typeof $planet_DataManager_poof$.$planet_follow_poof$>){
		if(this.$planet_call_pool_poof$.has(info.path)){
            let list = this.$planet_call_pool_poof$.get(info.path);
            if(list.length > 0) list.splice(list.indexOf(info.call), 1);
            else if(list.length <= 0) this.$planet_call_pool_poof$.delete(info.path);
		}
	}

	/**
     * 取消指定的监听
     * @param data 要监听的数据
     * @param key 要监听的字段
     * @param call 更新时触发的回调函数
	 */
	public static $planet_out_poof$<D extends Object, K extends abd.$planet_OmitKeys_poof$<D, Function>>(data: D, key: K, call: (old_value: D[K], new_value: D[K])=>void){
        let handle: $planet_PxiHandle_poof$<D> = this.$planet_record_poof$.get(this.$planet_id_map_poof$.get(data))[2];
		if(!handle) return void 0;

		let path = handle.$planet_path_poof$ + '.' + key.toString();
		this.$planet_cancel_poof$({path, call});
	}

	/** 指定的路径是否被监听 */
	public static $planet_hasListen_poof$<D extends Object, K extends abd.$planet_OmitKeys_poof$<D, Function>>(data: D, key: K){
		let id = this.$planet_id_map_poof$.get(data);
		if(id===undefined) return false;
		let handle = this.$planet_record_poof$.get(id)[2];
		if(handle===undefined) return false;
		let path = handle.$planet_path_poof$ + '.' + key.toString();
		let list = this.$planet_call_pool_poof$.get(path);
		return list===undefined ? false : list.length > 0;
	}


	/** 是否有任务正在执行中 */
	private static $planet_tasking_poof$: boolean = false;
	/** 更新日志记录 */
	private static $planet_record_map_poof$ = new Map<string, [any, any]>();

	/** 动态延迟，为了解决子节点并发更新时，父节点更新的重复触发造成的性能浪费，逻辑上不能完全防止，目前没有发现异常，暂时如此 */
	private static $planet_delay_poof$ = (()=>{
		let c = new abd.$planet_CountAverage_poof$();
		c.$planet_add_poof$(30);
		return c;
	})();
	private static $planet_delay_stamp_poof$ = performance.now();
	private static $planet_updateDelay_poof$(){
		let now = performance.now();
		let diff = now-$planet_DataManager_poof$.$planet_delay_stamp_poof$;
		$planet_DataManager_poof$.$planet_delay_stamp_poof$ = now;
		if(diff<=30 && diff>0) $planet_DataManager_poof$.$planet_delay_poof$.$planet_add_poof$(diff);
	}
	// ⬆⬆⬆ 该段代码的是为了防止，自节点的并发更新，导致父节点的更新事件重复触发的问题

	/** 打包生成任务 */
	private static $planet_packaging_poof$(){
		if(this.$planet_record_map_poof$.size===0) return void 0;

		let map = $planet_DataManager_poof$.$planet_record_map_poof$;
		$planet_DataManager_poof$.$planet_record_map_poof$ = new Map();

		let record = Array.from(map);
		let list = record.filter(el=>this.$planet_call_pool_poof$.has(el[0])).map(item=>{
			return {
				path: item[0],
				data: item[1]
			}
		});

		if(list.length>0) $planet_DataManager_poof$.$planet_taskLoop_poof$(list);
		else $planet_DataManager_poof$.$planet_tasking_poof$ = false;
	}

	/** 循环执行任务列表中的任务 */
	private static async $planet_taskLoop_poof$(list: {path: string, data: [any, any]}[]){
		while(list.length>0){
			let task = list.shift();
			//if(!task.path.includes('clock')) abd.$planet_log_poof$.$planet_tag_poof$('run task: green', task.path, ...task.data);
			await Promise.allSettled($planet_DataManager_poof$.$planet_call_pool_poof$.get(task.path).map(f=>new Promise((s, j)=>{
				f(...task.data);
				s(void 0);
			})));
			$planet_DataManager_poof$.$planet_distributeTask_poof$(task);
		}

		if($planet_DataManager_poof$.$planet_record_map_poof$.size > 0) $planet_DataManager_poof$.$planet_packaging_poof$();
		else $planet_DataManager_poof$.$planet_tasking_poof$ = false;
	}

	/** 触发一个任务支线 */
	private static async $planet_distributeTask_poof$(task: {path: string, data: [any, any]}){
		let path_list = task.path.split('.');
		// 触发被标记的代理监听
		if($planet_DataManager_poof$.$planet_monitor_call_poof$.has(path_list[0])) $planet_DataManager_poof$.$planet_monitor_call_poof$.get(path_list[0]).forEach(f=>f(task.path, ...task.data));
	}

	/**
	 * 发布更新日志
	 * @param path 更新路径
	 * @param old 原始值
	 * @param value 更新值
	 */
	public static $planet_publish_poof$(path: string, old: any, value: any){
		//abd.log.tag('publish-->:blue', DataManager.tasking, path, JSON.stringify([old, value]));

		$planet_DataManager_poof$.$planet_record_map_poof$.set(path, [old, value]);

		if(!$planet_DataManager_poof$.$planet_tasking_poof$){
			$planet_DataManager_poof$.$planet_tasking_poof$ = true;
		// ⬇⬇⬇ 该段代码的是为了防止，字节的并发更新，导致父节点的更新事件重复触发的问题
			let id = setTimeout((dm: typeof $planet_DataManager_poof$)=>{
				dm.$planet_packaging_poof$();
				clearTimeout(id);
			}, $planet_DataManager_poof$.$planet_delay_poof$.$planet_average_poof$, $planet_DataManager_poof$);
		}else $planet_DataManager_poof$.$planet_updateDelay_poof$();
		// ⬆⬆⬆ 该段代码的是为了防止，字节的并发更新，导致父节点的更新事件重复触发的问题
	}
}
